##  k8s. NodeSelector

1.  [Понятие NodeSelector в Kubernetes](#понятие-nodeselector-в-kubernetes)
2.  [Архитектура Kubernetes Nodes](#архитектура-kubernetes-nodes)
3.  [Работа с NodeSelector](#работа-с-nodeselector)
4.  [Практическая работа](#практическая-работа)

---

### Понятие NodeSelector в Kubernetes

1.  Что такое NodeSelector?

    *   NodeSelector в Kubernetes - это механизм, который позволяет задать условия выбора узлов (nodes) для размещения подов (pods). NodeSelector используется для определения, на каких узлах должны запускаться поды, основываясь на метках (labels) узлов. Каждый узел может иметь набор меток, и NodeSelector предоставляет возможность выбирать узлы, удовлетворяющие определенным критериям.

2.  Зачем нужен NodeSelector в Kubernetes?

    1.  Распределение нагрузки: NodeSelector позволяет равномерно распределять рабочие нагрузки между узлами. Вы можете указать критерии выбора узлов, чтобы поды размещались на узлах с определенными характеристиками, например, определенной архитектурой ЦП, объемом памяти или другими ресурсами.

    2.  Изоляция работы: NodeSelector также может использоваться для изоляции определенных задач или сервисов на отдельных узлах. Например, вы можете настроить NodeSelector для запуска подов базы данных только на узлах с высокой производительностью хранения данных.

    3.  Управление репликацией: NodeSelector помогает в управлении репликацией, размещая копии подов на различных узлах с учетом их характеристик. Это может быть полезным для обеспечения отказоустойчивости и повышения производительности.

3.  Как NodeSelector помогает в управлении ресурсами?

    1.  Оптимизация ресурсов: NodeSelector дает возможность оптимизировать распределение ресурсов в кластере Kubernetes. Поды с определенными требованиями к ресурсам могут быть направлены на узлы, способные предоставить необходимые ресурсы, уменьшая вероятность перегрузки или неэффективного использования ресурсов.
    2.  Управление нагрузкой: NodeSelector может использоваться для управления тем, какие узлы должны принимать нагрузку в зависимости от их текущей загруженности. Например, вы можете настроить NodeSelector так, чтобы поды с высокой вычислительной нагрузкой размещались на узлах с более мощными процессорами.
    3.  Адаптация к аппаратному обеспечению: NodeSelector обеспечивает возможность адаптации к различным характеристикам аппаратного обеспечения узлов. Это полезно при работе с разнообразным оборудованием, где некоторые узлы могут иметь специфические характеристики, например, GPU для параллельных вычислений.

---

### Архитектура Kubernetes Nodes

1.  Как устроены узлы (Nodes) в Kubernetes

    *   Устройство узлов (Nodes) в Kubernetes:

        *   Узлы в Kubernetes - это физические или виртуальные машины, на которых запускаются поды, базовые строительные блоки приложений в Kubernetes. Каждый узел состоит из нескольких компонентов:

        1.  Kubelet: Агент, работающий на каждом узле, отвечает за управление контейнерами на узле и взаимодействие с мастер-узлом. Принимает команды от мастера и управляет жизненным циклом подов на узле.

        2.  Kube-proxy: Сервис, отвечающий за управление сетевым взаимодействием между подами и обеспечивающий сервисы типа ClusterIP и LoadBalancer.

        3.  Container Runtime: Средство выполнения контейнеров, такое как Docker, containerd, или другие, которое отвечает за запуск и управление контейнерами на узле.

        4.  kubelet Service: Служба, предоставляющая API для взаимодействия с kubelet на узле.

        *   Узлы объединяются в кластер, и мастер-узел управляет их работой, принимая решения о том, на каких узлах должны быть размещены поды.

2.  Роль Node в обеспечении работы приложений

    *   Узлы в Kubernetes играют ключевую роль в обеспечении работы приложений. Важные аспекты и задачи, выполняемые узлами, включают:

        1.  Запуск и управление подами: Узлы запускают и управляют жизненным циклом подов. Kubelet следит за тем, чтобы все поды были в нужном состоянии, создавая, запуская и масштабируя контейнеры.

        2.  Управление ресурсами: Узлы выделяют и управляют ресурсами, такими как CPU и память, для подов. Это важно для эффективного использования ресурсов и предотвращения конфликтов при использовании общих ресурсов.

        3.  Сетевое взаимодействие: Kube-proxy обеспечивает сетевую связность между подами и управляет сервисами, обеспечивая доступность приложений.

        4.  Обработка событий и отчетность: Узлы собирают информацию о своем состоянии и отправляют ее мастер-узлу. Это позволяет мастер-узлу принимать решения на основе текущего состояния кластера.

        *   Узлы являются основными исполнителями задач в Kubernetes, выполняя инструкции мастер-узла для обеспечения непрерывной работы приложений.

3.  Влияние выделения ресурсов на работу приложений

    *   Эффективное использование ресурсов: Выделение ресурсов на узлах позволяет эффективно использовать вычислительные мощности и память. Это особенно важно в многозадачных средах, где множество приложений запущено на одном кластере.

    *   Предотвращение конфликтов ресурсов: Выделение ресурсов также предотвращает конфликты при использовании общих ресурсов, таких как CPU и память. Каждый под может быть ограничен в использовании ресурсов, что обеспечивает изоляцию и стабильность работы.

    *   Масштабируемость и отказоустойчивость: Эффективное выделение ресурсов способствует более гибкой масштабируемости и обеспечивает отказоустойчивость, поскольку приложения могут адаптироваться к изменениям нагрузки.

---

### Работа с NodeSelector

1.  Определение NodeSelector в манифестах Pod

    *   В манифестах Pod можно определить NodeSelector с использованием ключа nodeSelector. NodeSelector задается в виде пары метка-значение, и Pod будет запущен только на узлах, у которых соответствующие метки имеют указанные значения.

    *   Пример манифеста Pod с NodeSelector:

        ```yaml
        apiVersion: v1
        kind: Pod
        metadata:
        name: example-pod
        spec:
        containers:
        - name: nginx-container
            image: nginx
        nodeSelector:
            disktype: ssd
        ```

    *   В этом примере, Pod будет запущен только на узлах,
        у которых установлена метка disktype со значением ssd.

2.  Примеры использования NodeSelector

    *   Пример 1: Запуск на узлах с определенной операционной системой. В этом примере, Pod будет запущен только на узлах, у которых установлена метка os со значением linux.

        ```yaml
        apiVersion: v1
        kind: Pod
        metadata:
            name: os-specific-pod
        spec:
            containers:
            - name: ubuntu-container
                image: ubuntu
            nodeSelector:
                os: linux
        ```

    *   Пример 2: Выделение ресурсов для определенных подов. В этом примере, Pod будет запущен только на узлах, у которых установлена метка role со значением worker.

        ```yaml
        apiVersion: v1
        kind: Pod
        metadata:
            name: resource-specific-pod
        spec:
            containers:
            - name: resource-container
                image: busybox
            nodeSelector:
                role: worker
        ```

3.  Ограничения и лучшие практики при использовании NodeSelector

    *   Ограничения:
        1.  NodeSelector привязывает Pod к узлам, что может привести к неравномерному распределению нагрузки в кластере.
        2.  Использование слишком многочисленных NodeSelector может сделать кластер менее гибким.

    *   Лучшие практики:
        1.  Разумное использование меток: Метки узлов должны отражать их характеристики, такие как аппаратное обеспечение, ОС, роль и т.д.
        2.  Избегайте избыточности: Используйте NodeSelector там, где это действительно необходимо, чтобы избежать избыточности и сложности конфигурации.
        3.  Прозрачность и документация: Хорошо документируйте, какие метки используются для NodeSelector, чтобы упростить поддержку и понимание конфигурации.


    *   __Примечание__: Вместо NodeSelector, иногда более гибким решением может быть использование более высокоуровневых средств, таких как аффинитеты (affinity) и толерантности (tolerations), предоставляемых Kubernetes. Они обеспечивают более сложные и гибкие стратегии размещения.
---

### Практическая работа

0.  Откройте [эмулятор работы с k8s](https://labs.play-with-k8s.com)

1.  Создайте мастер-класс и два
    узла, которые соединены с ним
    (это была лабораторная работа из третьего раздела)

    *   Доказательством, что Вы сделали все верно должен быть такой вывод терминала

        ```bash
        $ kubectl get nodes
        NAME    STATUS     ROLES           AGE   VERSION
        node1   Ready      control-plane   55s   v1.27.2
        node2   Ready      <none>          11s   v1.27.2
        node3   Ready      <none>          4s    v1.27.2
        ```

2.  Перейдем в node1 и присвоим метку данному узлу

    ```bash
    kubectl label nodes node2 disktype=ssd
    ```

3.  Создадим новый под
    1.  Создадим манифест (touch pod.yaml)
    2.  Заполним этот манифест (vi pod.yaml)

        ```bash
        [node1 ~]$ cat pod.yaml
        apiVersion: v1
        kind: Pod
        metadata:
        name: demo
        labels:
            app: demo
            type: web
        spec:
        containers:
        - name: demo-nginx
            image: nginx
            ports:
            - containerPort: 80
        nodeSelector:
          disktype: ssd
        ```

    3.  Применим этот манифест

        ```bash
        kubectl apply -f pod.yaml
        ```

4.  Дождитесь окончания выполнения команды и просмотрите все поды и узлы, на которых они запущены.
    ```bash
    kubectl get pods -o wide
    ```

    *   В отчете подробно опишите вывод, который Вы получили

5.  Создадим Deployment

    1.  Создадим конфигурационный файл Deployment (touch deployment.yaml)

    2.  Заполним этот файл

        ```bash
        [node1 ~]$ cat deployment.yaml
        apiVersion: apps/v1
        kind: Deployment
        metadata:
        name: demo
        labels:
            app: demo
            type: web
        spec:
        replicas: 3
        selector:
            matchLabels:
            type: web
        template:
            metadata:
            labels:
                type: web
            spec:
            nodeSelector:
                disktype: ssd    
            containers:
            - name: demo-nginx
                image: nginx
                ports:
                - containerPort: 80
        [node1 ~]$ 
        ```

    3.  Применим конфигурацию Deployment

        ```bash
        kubectl apply -f deployment.yaml
        ```

    4.  В отчете необходимо дать пояснение для файла deployment.yaml

6.  Проверим Replicaset и поды, который были созданы в результате применения deployment.yaml

    ```bash
    # просмотрим реплики
    kubectl get rs
    ```
    
    ```bash
    # просмотрим все поды
    kubectl get pods
    ```

    *   В отчете поясните выводы этих команд

7.  Просмотрим на каких нодах были созданы поды

    ```bash
    kubectl get pods -o wide
    ```

    *   В отчете объясните вывод этой команды и поясните почему все поды были созданы на node2

На этом практическая часть по этому разделу закончена. В отчете подведите итоги того, что Вы сделали. Выполнение всех практических разделов в отчете должно сопровождаться скринами и ответами на соответствующие вопросы
